#include "Reg2NFA.h"

Reg2NFA::Reg2NFA(void)
{
	symbolGenerator = new HelpSymbolGenerator( 'q' );
}


Reg2NFA::~Reg2NFA(void)
{
}

list<Transition<string> > Reg2NFA::getAllTransitions()
{
	return allTransitions;
}

void Reg2NFA::toNFA( string postExpr )
{
	for( unsigned int i = 0; i < postExpr.length(); i++ )
	{
		switch( postExpr[i] )
		{
		case '|':
			{
				this->checkStartState();

				// eerste de rechtse blackbox erafhalen omdat die boven aan de stack staat.
				// de meest rechtse is diegene die er als laatste op is gezet
				BlackBox* bbRight = &myStack.top();
				myStack.pop();

				// daarna de volgende, dat is de linker blackbox
				BlackBox* bbLeft = &myStack.top();
				myStack.pop();
				
				// bovenste blackbox
				State* topLeft = new State();
				topLeft->helpSymbol = symbolGenerator->getNextSymbol();
				State* topRight = new State();
				topRight->helpSymbol = symbolGenerator->getNextSymbol();
				
				BlackBox *bbTop = new BlackBox();
				bbTop->expr = bbLeft->expr;
				bbTop->left = topLeft;
				bbTop->right = topRight;

				// onderste blackbox
				State* bottomLeft = new State();
				bottomLeft->helpSymbol = symbolGenerator->getNextSymbol();
				State* bottomRight = new State();
				bottomRight->helpSymbol = symbolGenerator->getNextSymbol();

				BlackBox* bbBottom = new BlackBox();
				bbBottom->expr = bbRight->expr;
				bbBottom->left = bottomLeft;
				bbBottom->right = bottomRight;
				
				// *** TRANSITIES MAKEN **
				createTransition( bbLeft->right->helpSymbol, bbTop->left->helpSymbol, EPSILON );
				createTransition( bbLeft->right->helpSymbol, bbBottom->left->helpSymbol, EPSILON );
				createTransition( bbTop->left->helpSymbol, bbTop->right->helpSymbol, bbTop->expr );
				createTransition( bbBottom->left->helpSymbol, bbBottom->right->helpSymbol, bbBottom->expr );
				createTransition( bbTop->right->helpSymbol, bbRight->left->helpSymbol, EPSILON );
				createTransition( bbBottom->right->helpSymbol, bbRight->left->helpSymbol, EPSILON );
				// ... nog steeds niet klaar
				


			break;
			}
		case '.': // concaternatie
			{ // accolades moet anders mag ik geen objecten instantieren van de compiler
				
				this->checkStartState();

				// eerste de rechtse blackbox erafhalen omdat die boven aan de stack staat.
				// de meest rechtse is diegene die er als laatste op is gezet
				BlackBox* bbRight = &myStack.top();
				myStack.pop();

				// daarna de volgende, dat is de linker blackbox
				BlackBox* bbLeft = &myStack.top();
				myStack.pop();
				
				// transitie samenstellen
				createTransition( bbLeft->right->helpSymbol, bbRight->left->helpSymbol, EPSILON );

				// blackboxen samenvoegen om terug op de stack te zetten
				bbLeft->next = bbRight;
				myStack.push( *bbLeft );
			break;
			}
		case '*':
			{
				this->checkStartState();
				
				BlackBox* bbRight = &myStack.top();
				myStack.pop();

				//BlackBox* bbRight = &myStack.top();
				//myStack.pop();

				State* leftState = new State();
				leftState->helpSymbol = symbolGenerator->getNextSymbol();
				
				State* rightState = new State();
				rightState->helpSymbol = symbolGenerator->getNextSymbol();
				
				//nieuwe linkse blackbox met epsilon naar bb left
				BlackBox *newBBLeft = new BlackBox();
				newBBLeft->expr = EPSILON;
				newBBLeft->left = leftState;
				newBBLeft->right = bbRight->left;

				BlackBox *newBBRight = new BlackBox();
				newBBRight->expr = EPSILON;
				newBBRight->left = bbRight->right;
				newBBRight->right = rightState;

				// transitie samenstellen
				createTransition( newBBLeft->left->helpSymbol, bbRight->left->helpSymbol, EPSILON );
				createTransition( bbRight->next->right->helpSymbol, newBBRight->right->helpSymbol, EPSILON );
				createTransition( newBBLeft->left->helpSymbol, newBBRight->right->helpSymbol, EPSILON );
				createTransition( bbRight->next->right->helpSymbol, bbRight->left->helpSymbol, EPSILON );

				newBBLeft->next = newBBRight;

				bbRight->next = newBBLeft;
				myStack.push( *bbRight );
			break;
			}
		default:
			this->checkStartState();
			
			State* sLeft = new State();
			sLeft->helpSymbol = symbolGenerator->getNextSymbol();

			State* sRight = new State();
			sRight->helpSymbol = symbolGenerator->getNextSymbol();

			BlackBox* box = new BlackBox();
			box->expr = postExpr[ i ];
			box->left = sLeft;
			box->right = sRight;
			myStack.push( *box );
			createTransition( sLeft->helpSymbol, sRight->helpSymbol, box->expr );
			break;
		}
	}
}

void Reg2NFA::checkStartState()
{
	if( symbolGenerator->isStartState() )
	{
		this->nfaStartSymbols.push_back( symbolGenerator->getNextSymbol() );
		// weer terug op 0 zetten want de eerst volgende terminal gebruikt het zelfde hulsymbool als startstate
		symbolGenerator->reset();
	}
}

void Reg2NFA::createTransition( string begin, string end, char expr )
{
	Transition< string > trans;
	trans.begin = begin;
	trans.end = end;
	trans.symbol = expr;
	// logging
	cout << "Transitie: " << begin << ">-<" << expr << ">-<" << end << endl;
	allTransitions.push_back( trans );

	
}